package com.atguigu.gulimall.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.constant.ProductConstant;
import com.atguigu.common.to.SkuEsModel;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.search.config.ApplicationConfig;
import com.atguigu.gulimall.search.feign.ProductFeign;
import com.atguigu.gulimall.search.service.SearchService;
import com.atguigu.gulimall.search.vo.AttrEntity;
import com.atguigu.gulimall.search.vo.SearchParam;
import com.atguigu.gulimall.search.vo.SearchResultVo;
import org.apache.lucene.search.TotalHits;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class SearchServiceImpl implements SearchService {
    @Autowired
    RestHighLevelClient restHighLevelClient;
    @Autowired
    private ProductFeign productFeign;
    //keyword=小米&sort=saleCount_desc/asc&hasStock=0/1&skuPrice=400_1900&brandId=1
    //&catalogId=1&attrs=1_3G:4G:5G&attrs=2_骁龙845&attrs=4_高清屏
    @Override
    public SearchResultVo search(SearchParam searchParam) {
        SearchResultVo searchResultVo = null;
        SearchRequest searchRequest = buildSearchRequest(searchParam);
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, ApplicationConfig.COMMONS_OPTIONS);
            searchResultVo = buildSearchResult(response,searchParam);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return searchResultVo;
    }

    private SearchRequest buildSearchRequest(SearchParam searchParam) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        if(!StringUtils.isEmpty(searchParam.getKeyword())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("skuTitle",searchParam.getKeyword()));
        }
        if(!StringUtils.isEmpty(searchParam.getCatalog3Id())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("catalogId",searchParam.getCatalog3Id()));
        }
        if(searchParam.getBrandId()!=null&&searchParam.getBrandId().size()>0){
            boolQueryBuilder.filter(QueryBuilders.termsQuery("brandId",searchParam.getBrandId()));
        }
        //attrs=1_3G:4G:5G&attrs=2_骁龙845&attrs=4_高清屏
        if(searchParam.getAttrs()!=null&&searchParam.getAttrs().size()>0){
            searchParam.getAttrs().forEach(attr->{
                String[] s = attr.split("_");
                String attrNo = s[0];
                String[] attrValue = s[1].split(":");
                BoolQueryBuilder boolQueryBuilder1 = new BoolQueryBuilder();
                boolQueryBuilder1.must(QueryBuilders.termQuery("attrs.attrId",attrNo));
                boolQueryBuilder1.must(QueryBuilders.termsQuery("attrs.attrValue",attrValue));
                NestedQueryBuilder nestedQueryBuilder = new NestedQueryBuilder("attrs",boolQueryBuilder1, ScoreMode.None);
                boolQueryBuilder.filter(nestedQueryBuilder);
            });
        }
        if(!StringUtils.isEmpty(searchParam.getHasStock())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("hasStock",searchParam.getHasStock()==1));
        }
        if(!StringUtils.isEmpty(searchParam.getSkuPrice())){
            String s = searchParam.getSkuPrice().toString();
            String[] s1 = s.split("_");
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("skuPrice");
            if(s1.length==2){
                rangeQueryBuilder.gte(s1[0]).lte(s1[1]);
            }else if (s1.length==1){
                if(s.startsWith("-")){
                    rangeQueryBuilder.lte(s1[0]);
                }else if (s.endsWith("_")){
                    rangeQueryBuilder.gte(s1[0]);
                }
            }
            boolQueryBuilder.filter(rangeQueryBuilder);
        }

        //封装所有的查询条件
        searchSourceBuilder.query(boolQueryBuilder);

        //排序
        if(!StringUtils.isEmpty(searchParam.getSort())){
            String s = searchParam.getSort().toString();
            String[] s1 = s.split("_");
            searchSourceBuilder.sort(s1[0],s1[1].equals("asc")?SortOrder.ASC:SortOrder.DESC);
        }
        //分页
        searchSourceBuilder.from((searchParam.getPageNum()-1)* ProductConstant.PRODUCT_PAGESIZE);
        searchSourceBuilder.size(ProductConstant.PRODUCT_PAGESIZE);
        //高亮
        if(!StringUtils.isEmpty(searchParam.getKeyword())){
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field(new HighlightBuilder.Field("skuTitle"));
            highlightBuilder.preTags("<font color='red'>");
            highlightBuilder.postTags("</font>");
            searchSourceBuilder.highlighter(highlightBuilder);
        }
        //System.out.println("打印数据");
        //System.out.println(searchSourceBuilder.toString());
        SearchRequest searchRequest = new SearchRequest(new String[]{ProductConstant.PRODUCT_UP_INDEX},searchSourceBuilder);

        //聚合
        TermsAggregationBuilder brand_id_agg = AggregationBuilders.terms("brand_id_agg");
        brand_id_agg.field("brandId").size(50);
        brand_id_agg.subAggregation(AggregationBuilders.terms("brand_name_agg").field("brandName").size(50));
        brand_id_agg.subAggregation(AggregationBuilders.terms("brand_img_agg").field("brandImg").size(50));
        searchSourceBuilder.aggregation(brand_id_agg);

        TermsAggregationBuilder catalog_id_agg = AggregationBuilders.terms("catalog_id_agg");
        catalog_id_agg.field("catalogId").size(50);
        catalog_id_agg.subAggregation(AggregationBuilders.terms("catalog_name_agg").field("catalogName").size(50));
        searchSourceBuilder.aggregation(catalog_id_agg);

        NestedAggregationBuilder attrs_nest_agg = AggregationBuilders.nested("attrs_nest_agg","attrs");
        TermsAggregationBuilder attrs_id_agg = AggregationBuilders.terms("attrs_id_agg").field("attrs.attrId");
        attrs_nest_agg.subAggregation(attrs_id_agg);
        attrs_id_agg.subAggregation(AggregationBuilders.terms("attrs_name_agg").field("attrs.attrName").size(50));
        attrs_id_agg.subAggregation(AggregationBuilders.terms("attrs_value_agg").field("attrs.attrValue").size(50));

        searchSourceBuilder.aggregation(attrs_nest_agg);
        System.out.println("打印数据1");
        System.out.println(searchSourceBuilder.toString());
        return searchRequest;
    }

    private SearchResultVo buildSearchResult(SearchResponse response, SearchParam searchParam) {
        System.out.println("------------------------");
        SearchResultVo searchResultVo = new SearchResultVo();
        SearchHit[] hits = response.getHits().getHits();
        List<SkuEsModel> skuEsModels = Arrays.stream(hits).map(item -> {
            String sourceAsString = item.getSourceAsString();
            SkuEsModel esModel = JSON.parseObject(sourceAsString, SkuEsModel.class);

            //设置高亮
            if(!StringUtils.isEmpty(searchParam.getKeyword())){
                HighlightField skuTitle = item.getHighlightFields().get("skuTitle");
                String title = skuTitle.getFragments()[0].toString();
                esModel.setSkuTitle(title);
            }
            return esModel;
        }).collect(Collectors.toList());
        //保存esModel
        searchResultVo.setSkuEsModelList(skuEsModels);
        //保存BrandVos
        List<SearchResultVo.BrandVo> brandVos = new ArrayList<>();
        ParsedLongTerms brand_id_agg = response.getAggregations().get("brand_id_agg");
        for (Terms.Bucket bucket : brand_id_agg.getBuckets()) {
            SearchResultVo.BrandVo brandVo = new SearchResultVo.BrandVo();
            int brandId = bucket.getKeyAsNumber().intValue();

            ParsedStringTerms brand_name_agg = bucket.getAggregations().get("brand_name_agg");
            String brandName = brand_name_agg.getBuckets().get(0).getKeyAsString();

            ParsedStringTerms brand_img_agg = bucket.getAggregations().get("brand_img_agg");
            String brandImg = brand_img_agg.getBuckets().get(0).getKeyAsString();

            brandVo.setBrandId((long) brandId);
            brandVo.setBrandImg(brandImg);
            brandVo.setBrandName(brandName);
            brandVos.add(brandVo);
        }
        searchResultVo.setBrandVos(brandVos);

        //保存CatalogVos
        List<SearchResultVo.CatalogVo> catalogVos = new ArrayList<>();
        ParsedLongTerms catalog_id_agg = response.getAggregations().get("catalog_id_agg");
        for (Terms.Bucket bucket : catalog_id_agg.getBuckets()) {
            SearchResultVo.CatalogVo catalogVo = new SearchResultVo.CatalogVo();
            long catalogId = bucket.getKeyAsNumber().longValue();

            ParsedStringTerms catalog_name_agg = bucket.getAggregations().get("catalog_name_agg");
            String catalogName = catalog_name_agg.getBuckets().get(0).getKeyAsString();

            catalogVo.setCatalogId(catalogId);
            catalogVo.setCatalogName(catalogName);
            catalogVos.add(catalogVo);
        }
        searchResultVo.setCatalogVos(catalogVos);

        //保存attrVos
        List<SearchResultVo.AttrVo> attrVos = new ArrayList<>();
        ParsedNested attrs_nest_agg = response.getAggregations().get("attrs_nest_agg");
        ParsedLongTerms attrs_id_agg = attrs_nest_agg.getAggregations().get("attrs_id_agg");
        for (Terms.Bucket bucket : attrs_id_agg.getBuckets()) {
            SearchResultVo.AttrVo attrVo = new SearchResultVo.AttrVo();
            long attrId = bucket.getKeyAsNumber().longValue();

            ParsedStringTerms attrs_name_agg = bucket.getAggregations().get("attrs_name_agg");
            String attrName = attrs_name_agg.getBuckets().get(0).getKeyAsString();

            ParsedStringTerms attrs_value_agg = bucket.getAggregations().get("attrs_value_agg");
            List<String> attrValueList = attrs_value_agg.getBuckets().stream().map(bucket1 -> {
                String attrValue = bucket1.getKeyAsString();
                return attrValue;
            }).collect(Collectors.toList());

            attrVo.setAttrId(attrId);
            attrVo.setAttrName(attrName);
            attrVo.setAttrValues(attrValueList);
            attrVos.add(attrVo);
        }
        searchResultVo.setAttrVos(attrVos);

        TotalHits totalHits = response.getHits().getTotalHits();

        int total = (int) totalHits.value;
        //设置当前页
        searchResultVo.setPageNum(searchParam.getPageNum());
        //设置总记录条数
        searchResultVo.setTotal(total);
        int totalPage = total%ProductConstant.PRODUCT_PAGESIZE==0?total/ProductConstant.PRODUCT_PAGESIZE:total/ProductConstant.PRODUCT_PAGESIZE+1;
        //设置页码
        List<Integer> pageNavs = new ArrayList<>();
        for (int i = 1; i < totalPage; i++) {
            pageNavs.add(i);
        }
        searchResultVo.setPageNavs(pageNavs);
        //设置总页数
        searchResultVo.setTotalPage(totalPage);


        //面包屑导航
        if(searchParam.getAttrs()!=null&&searchParam.getAttrs().size()>0){
            List<String> attrs = searchParam.getAttrs();
            List<SearchResultVo.NavVo> navVoList = attrs.stream().map(attr -> {
                SearchResultVo.NavVo navVo = new SearchResultVo.NavVo();
                String[] s = attr.split("_");
                String attrValue = s[1];
                R r = productFeign.attrInfo(Long.parseLong(s[0]));
                if (r.getCode() == 0) {
                    AttrEntity attrEntity = r.getData("data", new TypeReference<AttrEntity>() {
                    });
                    navVo.setNavName(attrEntity.getAttrName());
                } else {
                    navVo.setNavName(s[0]);
                }
                navVo.setNavValue(attrValue);

                try {
                    String navLink = searchParam.getNavLink();
                    String encode = URLEncoder.encode(attr, "UTF-8");
                    String replace = navLink.replace("&attrs=" + encode, "");
                    navVo.setLink("http://search.gulimall.com/list.html?"+replace);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                return navVo;
            }).collect(Collectors.toList());
            searchResultVo.setNavs(navVoList);
        }

        System.out.println("=================");
        return searchResultVo;
    }


}
